﻿//-----------------------------------------------------------------------
// <copyright file="MainForm.cs" company="MSCRMTools">
//     Copyright © MSCRMTools. All rights reserved.
// </copyright>
// <author>tanguy92</author>
// <date>21/02/2011</date>
// <codeplexurl>http://searchablepropertyupdater.codeplex.com</codeplexurl>
// <summary>Application main form</summary>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using McTools.Xrm.Connection;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using SearchablePropertyUpdater2011.Helpers;
using Tanguy.WinForm.Utilities.DelegatesHelpers;
using System.Diagnostics;

namespace SearchablePropertyUpdater2011
{
    /// <summary>
    /// Application main form
    /// </summary>
    public sealed partial class MainForm : Form
    {
        #region Variables

        /// <summary>
        /// Original value for searchable property
        /// </summary>
        Dictionary<string, bool> _attributesOriginalState;

        /// <summary>
        /// Crm organization service
        /// </summary>
        IOrganizationService _service;

        /// <summary>
        /// Connection manager
        /// </summary>
        readonly ConnectionManager _cManager;

        /// <summary>
        /// Control that holds list of connections
        /// </summary>
        readonly CrmConnectionStatusBar _ccsb;

        /// <summary>
        /// Current Attributes list order column index
        /// </summary>
        int _currentAttributesColumnOrder;

        #endregion Variables

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class MainForm
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            // Displays application version
            Text += " (v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() + ")"; 

            // Prepare connection statusbar control
            _cManager = new ConnectionManager(this);
            _ccsb = new CrmConnectionStatusBar(_cManager);
            _cManager.ConnectionSucceed += CManagerConnectionSucceed;
            _cManager.ConnectionFailed += CManagerConnectionFailed;
            _cManager.StepChanged += CManagerStepChanged;

            _ccsb = new CrmConnectionStatusBar(_cManager);
            Controls.Add(_ccsb);
        }

        #endregion Constructor

        #region Connection handlers

        void CManagerStepChanged(object sender, StepChangedEventArgs e)
        {
            _ccsb.SetMessage(e.CurrentStep);
        }

        void CManagerConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            _ccsb.SetMessage(e.FailureReason);
            MessageBox.Show(e.FailureReason, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        void CManagerConnectionSucceed(object sender, ConnectionSucceedEventArgs e)
        {
            _ccsb.RebuildConnectionList();

            _service = e.OrganizationService;
            _ccsb.SetConnectionStatus(true, e.ConnectionDetail);

            TsbLoadEntitiesClick(null, null);
        }

        #endregion

        #region Methods

        #region Fill Entities

        private void TsbLoadEntitiesClick(object sender, EventArgs e)
        {
            if (_service == null)
            {
                _cManager.AskForConnection(null);
            }
            else
            {
                lvEntities.Items.Clear();
                lvAttributes.Items.Clear();
                btnCheck.Enabled = false;
                btnCheckAttrOnForms.Enabled = false;
                btnResetAttributes.Enabled = false;
                gbEntities.Enabled = false;
                tsbPublishEntity.Enabled = false;
                tsbSaveAttributes.Enabled = false;

                var bwFillEntities = new BackgroundWorker();
                bwFillEntities.DoWork += BwFillEntitiesDoWork;
                bwFillEntities.RunWorkerCompleted += BwFillEntitiesRunWorkerCompleted;
                bwFillEntities.RunWorkerAsync();
            }
        }

        void BwFillEntitiesRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                string errorMessage = CrmExceptionHelper.GetErrorMessage(e.Error, true);
                CommonDelegates.DisplayMessageBox(this, errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void BwFillEntitiesDoWork(object sender, DoWorkEventArgs e)
        {
            CommonDelegates.SetCursor(this, Cursors.WaitCursor);
            _ccsb.SetMessage("Loading entities ...");

            // Caching entities
            List<EntityMetadata> entities = MetadataHelper.RetrieveEntities(_service);

            _ccsb.SetMessage("Displaying entities...");

            // Filling entities list
            FillEntitiesList(entities);

            _ccsb.SetMessage(string.Empty);
            CommonDelegates.SetCursor(this, Cursors.Default);
        }

        /// <summary>
        /// Fills the entities listview
        /// </summary>
        public void FillEntitiesList(List<EntityMetadata> entities)
        {
            try
            {
                ListViewDelegates.ClearItems(lvEntities);

                foreach (EntityMetadata emd in entities)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = emd.DisplayName.UserLocalizedLabel.Label;
                    item.SubItems.Add(emd.LogicalName);
                    item.Tag = emd;
                    ListViewDelegates.AddItem(lvEntities, item);
                }

                ColumnHeader header = new ColumnHeader()
                {
                    Text = "Display name",
                    Width = 160
                };

                ListViewDelegates.AddColumn(lvEntities, header);
                GroupBoxDelegates.SetEnableState(gbEntities, true);
            }
            catch (Exception error)
            {
                string errorMessage = CrmExceptionHelper.GetErrorMessage(error, true);
                CommonDelegates.DisplayMessageBox(this, errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Fill Attributes

        private void LvEntitiesSelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvEntities.SelectedItems.Count > 0)
            {
                lvAttributes.Items.Clear();

                var emd = (EntityMetadata)lvEntities.SelectedItems[0].Tag;

                CommonDelegates.SetCursor(this, Cursors.WaitCursor);
                _ccsb.SetMessage("Loading attributes...");

                var bwFillAttributes = new BackgroundWorker();
                bwFillAttributes.DoWork += BwFillAttributesDoWork;
                bwFillAttributes.RunWorkerCompleted += BwFillAttributesRunWorkerCompleted;
                bwFillAttributes.RunWorkerAsync(emd.LogicalName);
            }
        }

        void BwFillAttributesDoWork(object sender, DoWorkEventArgs e)
        {
            var emd = MetadataHelper.RetrieveEntity(e.Argument.ToString(), _service);

            // Retrieve forms for this entity
            var allFormsDoc = MetadataHelper.RetrieveEntityForms(emd.LogicalName, _service);

            _attributesOriginalState = new Dictionary<string, bool>();

            foreach (var amd in emd.Attributes)
            {
                if (amd.AttributeType.Value != AttributeTypeCode.Virtual
                    && string.IsNullOrEmpty(amd.AttributeOf))
                {
                    bool searchable = amd.IsValidForAdvancedFind.Value;
                    string label = amd.DisplayName.UserLocalizedLabel != null ? amd.DisplayName.UserLocalizedLabel.Label : "N/A";

                    var item = new ListViewItem(label);
                    item.SubItems.Add(amd.LogicalName);
                    item.SubItems.Add(amd.IsValidForAdvancedFind.CanBeChanged.ToString());
                    item.SubItems.Add(amd.IsCustomizable.Value.ToString());
                    item.SubItems.Add((allFormsDoc.SelectSingleNode("//control[@datafieldname='" + amd.LogicalName + "']") != null).ToString());
                   
                    item.Tag = amd;
                    item.Checked = searchable;

                    if (!amd.IsValidForAdvancedFind.CanBeChanged || !amd.IsCustomizable.Value)
                    {
                        item.ForeColor = Color.Gray;
                    }

                    _attributesOriginalState.Add(amd.LogicalName, searchable);
                    
                    ListViewDelegates.AddItem(lvAttributes, item);
                }
            }
        }

        void BwFillAttributesRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            CommonDelegates.SetCursor(this, Cursors.Default);
            
            if (e.Cancelled)
            {
                _ccsb.SetMessage("Process canceled");
                MessageBox.Show(this, "Process canceled", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else if(e.Error != null)
            {
                _ccsb.SetMessage(e.Error.Message);
                MessageBox.Show(this, e.Error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                _ccsb.SetMessage(string.Empty);
                
                lvAttributes.Enabled = true;
                tsbSaveAttributes.Enabled = true;
                tsbPublishEntity.Enabled = true;
                btnResetAttributes.Enabled = true;
                btnCheck.Enabled = true;
                btnCheckAttrOnForms.Enabled = true;
                gbAttributes.Enabled = true;
            }
        }

        #endregion

        #region Save Attributes
 
        private void TsbSaveAttributesClick(object sender, EventArgs e)
        {
            var items = (from ListViewItem item in lvAttributes.Items select (ListViewItem) item.Clone()).ToList();

            var uaForm = new Forms.UpdateAttributesForm(_service, items)
                             {StartPosition = FormStartPosition.CenterParent};
            uaForm.ShowDialog();
        } 
        
        #endregion

        #region Publish Entity

        private void TsbPublishEntityClick(object sender, EventArgs e)
        {
            if (lvEntities.SelectedItems.Count > 0)
            {
                tsbPublishEntity.Enabled = false;
                tsbSaveAttributes.Enabled = false;
                tsbLoadEntities.Enabled = false;

                CommonDelegates.SetCursor(this, Cursors.WaitCursor);
                _ccsb.SetMessage("Publishing entity...");

                var bwPublish = new BackgroundWorker();
                bwPublish.DoWork += BwPublishDoWork;
                bwPublish.RunWorkerCompleted += BwPublishRunWorkerCompleted;
                bwPublish.RunWorkerAsync(lvEntities.SelectedItems[0].Tag);
            }
        }

        void BwPublishRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _ccsb.SetMessage(string.Empty);
            CommonDelegates.SetCursor(this, Cursors.Default);

            tsbPublishEntity.Enabled = true;
            tsbSaveAttributes.Enabled = true;
            tsbLoadEntities.Enabled = true;
        }

        void BwPublishDoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                var currentEmd = (EntityMetadata)e.Argument;

                var pubRequest = new PublishXmlRequest
                                     {
                                         ParameterXml =
                                             string.Format(
                                                 @"<importexportxml>
                                                           <entities>
                                                              <entity>{0}</entity>
                                                           </entities>
                                                           <nodes/><securityroles/><settings/><workflows/>
                                                        </importexportxml>",
                                                 currentEmd.LogicalName)
                                     };

                _service.Execute(pubRequest);

                CommonDelegates.DisplayMessageBox(this, "Entity published!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception error)
            {
                string errorMessage = CrmExceptionHelper.GetErrorMessage(error, false);
                CommonDelegates.DisplayMessageBox(this, error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        private void BtnResetAttributesClick(object sender, EventArgs e)
        {
            foreach (ListViewItem item in lvAttributes.Items)
            {
                if (_attributesOriginalState.ContainsKey(item.SubItems[1].Text))
                {
                    item.Checked = _attributesOriginalState[item.SubItems[1].Text];
                }
            }
        }

        private void BtnCheckClick(object sender, EventArgs e)
        {
            foreach (ListViewItem item in lvAttributes.Items)
            {
                item.Checked = ((Button)sender).Text == "Check All";
            }

            if (((Button)sender).Text == "Check All")
            {
                ((Button)sender).Text = "Clear All";
            }
            else
            {
                ((Button)sender).Text = "Check All";
            }
        }

        private void BtnCheckAttrOnFormsClick(object sender, EventArgs e)
        {
            foreach (ListViewItem item in lvAttributes.Items)
            {
                if (item.SubItems[4].Text.ToLower() == "true")
                {
                    item.Checked = true;
                }
                else
                {
                    item.Checked = false;
                }
            }
        }

        private void TsbAboutClick(object sender, EventArgs e)
        {
            var aForm = new AboutForm {StartPosition = FormStartPosition.CenterParent};
            aForm.ShowDialog();
        }

        #endregion

        #region Column Sorting Handlers

        private void LvEntitiesColumnClick(object sender, ColumnClickEventArgs e)
        {
            lvEntities.SelectedItems.Clear();
            lvAttributes.Items.Clear();
            gbAttributes.Enabled = false; 
            tsbSaveAttributes.Enabled = false;
            tsbPublishEntity.Enabled = false;
            btnResetAttributes.Enabled = false;
            btnCheck.Enabled = false;
            btnCheckAttrOnForms.Enabled = false;

            if (lvEntities.Sorting == SortOrder.Ascending)
            {
                lvEntities.Sorting = SortOrder.Descending;
            }
            else
            {
                lvEntities.Sorting = SortOrder.Ascending;
            }

            lvEntities.ListViewItemSorter = new ListViewItemComparer(e.Column, lvEntities.Sorting);
        }

        private void LvAttributesColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == _currentAttributesColumnOrder)
            {
                if (lvAttributes.Sorting == SortOrder.Ascending)
                {
                    lvAttributes.Sorting = SortOrder.Descending;
                }
                else
                {
                    lvAttributes.Sorting = SortOrder.Ascending;
                }

                lvAttributes.ListViewItemSorter = new ListViewItemComparer(e.Column, lvAttributes.Sorting);
            }
            else
            {
                _currentAttributesColumnOrder = e.Column;
                lvAttributes.ListViewItemSorter = new ListViewItemComparer(e.Column, SortOrder.Ascending);
            }
        }

        #endregion

        private void TsbRateClick(object sender, EventArgs e)
        {
            Process.Start("http://searchpropupdater.codeplex.com/releases");
        }

        private void TsbDiscussClick(object sender, EventArgs e)
        {
            Process.Start("http://searchpropupdater.codeplex.com/discussions");
        }

        private void TsbReportBugClick(object sender, EventArgs e)
        {
            Process.Start("http://searchpropupdater.codeplex.com/WorkItem/Create");
        }

        private void TsbDonateClick(object sender, EventArgs e)
        {
            string url = "";

            string business = "tanguy92@hotmail.com";  // your paypal email
            string description = "Donation%20for%20MSCRM%20Tools";            // '%20' represents a space. remember HTML!
            string country = "FR";                  // AU, US, etc.
            string currency = "EUR";                 // AUD, USD, etc.

            url += "https://www.paypal.com/cgi-bin/webscr" +
                "?cmd=" + "_donations" +
                "&business=" + business +
                "&lc=" + country +
                "&item_name=" + description +
                "&currency_code=" + currency +
                "&bn=" + "PP%2dDonationsBF";

            System.Diagnostics.Process.Start(url);

        }
    }
}